﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DXBase.Async
{
	//http://blogs.msdn.com/b/pfxteam/
	//http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx
	public class AsyncLock
	{
		private readonly AsyncSemaphore m_semaphore;
		private readonly Task<IDisposable> m_releaser;

		public AsyncLock()
		{
			m_semaphore = new AsyncSemaphore(1);
			m_releaser = Task.FromResult((IDisposable)new Releaser(this));
		}

		public Task<IDisposable> LockAsync()
		{
			var wait = m_semaphore.WaitAsync();
			return wait.IsCompleted ?
				m_releaser :
				wait.ContinueWith((_, state) => (IDisposable)new Releaser((AsyncLock)state),
					this, CancellationToken.None,
					TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
		}

		class Releaser : IDisposable
		{
			private readonly AsyncLock m_toRelease;

			internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; }

			public void Dispose()
			{
				if (m_toRelease != null)
					m_toRelease.m_semaphore.Release();
			}
		}
	}
}
